#include "key.h"

using namespace std;

//RSA key
//produce a random part of RSA key:(d,n),(e,n)
RsaKey::RsaKey(int32_t colMsg_size)                
{	
	limit = 1000;
	while (4*limit*limit < colMsg_size) {                                        //make sure that n is biger than colMsg_size             
		limit *= 2;
	}
    int i = 0, k = 0, p = 0, q = 0, m = 0, n = 0, d = 0, e = 0, l = 0, j = 0;    //produce a array of prime number from limit to 2*limit
 	int *prime = new int[limit];
	for( i = limit / 2 * 2 + 1; i < 2 * limit; i += 2 ) {
         if( isPrime( i ) ) {
             prime[ k ] = i;
             k++;
         }
	}
    srand( ( unsigned int )time( NULL ) );                                       //produce p,q from the array of prime number                                
    j = rand() % k;
    p = prime[ j ];    
    j = rand() % k;
    q = prime[ j ];
    n = p * q;
    m = ( p - 1 ) * ( q - 1 );
    l = rand() % ( m / 2 );
	for( i = l / 2 * 2 + 1; i < m; i += 2 ) {
         if( isPrime( i ) ) {
             d = i;
             e = mulinv( d, m );                                                 //produce d,e
             break;
         }	
	}
    rsa_d = d;
	rsa_e = e;
	rsa_n = n;    
}

int RsaKey::get_d()
{
	return rsa_d;
}

int RsaKey::get_e() 
{
	return rsa_e;
}

int RsaKey::get_n()
{
	return rsa_n;
}

//ServerPublicKey 
//public key n,e sent to client
key_t ServerPublicKey::getN() const
{
	return n;
}

key_t ServerPublicKey::getE() const 
{
	return e;
}

const Serialization ServerPublicKey::getSerialization() const 
{					
	char *nePtr = new char[8];
	*((int32_t*)(nePtr)) = n;
	*((int32_t*)(nePtr)+1) = e;
	Serialization sl( nePtr, 8 );
	return sl;
}

ServerPublicKey* ServerPublicKey::fromRaw(Serialization s) 
{		
	char *nePtr = s.getData();	
	int n_tmp = *((int32_t*)nePtr);
    int e_tmp = *((int32_t*)nePtr+1);
	return new ServerPublicKey(n_tmp,e_tmp);
}

//RabinServerKey
RabinServerKey::RabinServerKey(int32_t dd,int32_t n,int32_t e)
{	
	d = dd;
	pubkey = new ServerPublicKey(n,e);
}

RabinServerKey::~RabinServerKey()
{	
	delete pubkey;
}

const ServerPublicKey* RabinServerKey::getPublic() const
{
	return pubkey;
}

CipherMessage* RabinServerKey::encrypt(const Message* m,const Message* x,const CipherMessage* v) const  
{	
	return new CipherMessage( rabinOTServerEncode(v->getRaw(), m->getData(), x->getData(), d, pubkey->getN()) );
}

RabinServerKey* RabinServerKey::fromRandom(int colMsg_size) 
{	
    RsaKey *rk = new RsaKey(colMsg_size);
	return new RabinServerKey(rk->get_d(),rk->get_n(),rk->get_e());
} 

//class ClientKey
CipherMessage* ClientKey::coencrypt(const Message* msg, const ServerPublicKey* pubkey) const          
{	
	cmsg_t v = rabinOTClientEncode(msg->getData(),k, pubkey->getN(), pubkey->getE());	
	return new CipherMessage(v);
}

Message* ClientKey::decrypt(const CipherMessage* cmsg) const                                          
{								
	msg_t b =  rabinOTDecode(cmsg->getRaw(),k);	
	return new Message(b);
}

ClientKey* ClientKey::fromRandom() 
{									
	 srand((unsigned)time(NULL));
	 key_t kk = rand()%256;	 
	 return new ClientKey(kk);
}
